<template>
  <el-table 
    :data="tableData" 
    v-loading="isLoading" 
    @row-click="rowClick">
    <!-- 数据列 -->
    <template v-for="(item, index) in tableOptions" :key="index">
      <el-table-column
        :label="item.label"
        :prop="item.prop"
        :align="item.align"
        :width="item.width"
      >
        <template #default="scope">
          <!-- 1. 有编辑行 -->
          <template v-if="scope.row.isEdit">
            <el-input  
              v-model="scope.row[item.prop]"
            ></el-input>
          </template>
          <!-- 2. 无编辑行 -->
          <template v-else>
            <!-- 自定义列 提供插槽 -->
            <slot v-if="item.slot" :name="item.slot" :scope="scope"></slot>
            <!-- 可编辑 -->
            <template v-else-if="item.editable">
              <!-- 编辑状态 -->
              <div 
                v-if="scope.$index + scope.column.id === currentEditId" 
                class="table-edit">
                <el-input  
                  v-model="scope.row[item.prop]"
                ></el-input>
                <!-- 保存/取消 编辑 -->
                <slot 
                  name="editCell" 
                  v-if="$slots.editCell" 
                  :scope="scope"
                  class="edit-slot">
                </slot>
                <div v-else class="icon-wrap">
                  <el-icon-check class="icon-check" @click.stop="saveEdit(scope)"/>
                  <el-icon-close class="icon-close" @click.stop="cancelEdit(scope)"/>
                </div>
              </div>
              <!-- 非编辑状态 -->
              <div v-else class="table-edit">
                <div>{{ scope.row[item.prop] }}</div>
                <div @click.stop="currentEditClick(scope)">
                  <component :is="`el-icon${toLine(editIcon)}`"></component>
                </div>
              </div>
            </template>
            <!-- 普通单元格 -->
            <span v-else>{{ scope.row[item.prop] }}</span>
          </template>
        </template>
      </el-table-column>
    </template>
    <div></div>
    <!-- 操作列 -->
    <el-table-column
      v-if="actionOptions"
      :label="actionOptions.label"
      :align="actionOptions.align"
      :width="actionOptions.width"
    >
      <template #default="scope">
        <!-- 编辑状态 -->
        <template v-if="scope.row.isEdit">
          <!-- 有插槽 -->
          <slot v-if="$slots.editRow" name="editRow" :scope="scope"></slot>
          <!-- 默认 -->
          <div v-else class="icon-wrap">
            <el-icon-check class="icon-check" @click.stop="saveRowEdit(scope)"/>
            <el-icon-close class="icon-close" @click.stop="cancelRowEdit(scope)"/>
          </div>
        </template>
        <!-- 正常状态 -->
        <slot v-else name="action" :scope="scope"></slot>
      </template>
    </el-table-column>
  </el-table>
</template>

<script lang='ts' setup>
import { PropType, computed, ref, watch } from 'vue'
import cloneDeep from 'lodash/cloneDeep'
import { toLine } from '../../../utils/toLine'
import { TableOptions } from './types'

let props = defineProps({
  // 表格配置
  options: {
    type: Array as PropType<TableOptions[]>,
    required: true
  },
  // 表格数据
  data: {
    type: Array as PropType<any[]>,
    required: true
  },
  // 可编辑单元格显示图标
  editIcon: {
    type: String,
    default: 'Edit'
  },
  // 是否可以编辑行
  isEditRow: {
    type: Boolean,
    default: false
  },
  // 编辑行按钮标识
  editRowIndex: {
    type: Boolean,
    default: false
  }
})

// loading
let isLoading = computed(() => !props.data || !props.data.length)

// 普通列
let tableOptions = computed(() => props.options.filter(item => !item.action))

// 操作列
let actionOptions = computed(() => props.options.find(item => item.action))

// 拷贝表格数据
let tableData = ref<any[]>(cloneDeep(props.data))
// 点击编辑单元格
let currentEditId = ref('')
let currentEditClick = (scope: any) => {
  currentEditId.value = scope.$index + scope.column.id
}
let emits = defineEmits(['confirm', 'cancel', 'update:editRowIndex'])
// 保留单元格编辑结果
let saveEdit = (scope: any) => {
  currentEditId.value = ''
  // 修改父组件的数据
  props.data[scope.$index] = scope.row
}
// 取消单元格编辑结果
let cancelEdit = (scope: any) => {
  currentEditId.value = ''
  // 修改子组件的数据
  tableData.value[scope.$index] = props.data[scope.$index]
}

// 监听表格数据的变化
watch(
  () => props.data, 
  val => {
    tableData.value = cloneDeep(val)
    tableData.value.map(item => {
      // 代表当前行是否可编辑
      item.isEdit = false
    })
  }, 
  {
    deep: true,
    immediate: true
  }
)
// 点击操作项编辑按钮的事件
let rowClick = (row: any, column: any) => {
  // 表格支持编辑行 && 点击操作按钮
  if(props.isEditRow && props.editRowIndex) {
    row.isEdit = true
  }
  // 重置其他行的isEditRow
  tableData.value.map((item) => {
    if(item !== row) {
      item.isEdit = false
    }
  })
  // 重置按钮标识
  emits('update:editRowIndex', false)
}
// 保存行编辑结果
let saveRowEdit = (scope: any) => {
  scope.row.isEdit = false
  // 重置按钮标识
  emits('update:editRowIndex', false)
  // 修改父组件的数据
  props.data[scope.$index] = scope.row
}
// 取消行编辑结果
let cancelRowEdit = (scope: any) => {
  scope.row.isEdit = false
  // 重置按钮标识
  emits('update:editRowIndex', false)
  // 修改子组件的数据
  tableData.value[scope.$index] = props.data[scope.$index]
}
</script>

<style lang='scss' scoped>
.table-edit {
  display: flex;
  justify-cotent: center;
  align-item: center;
}
svg {
  width: 1.5em;
  height: 1.5em;
  margin: 5px;
  cursor: pointer;
}
.icon-wrap {
  width: 100px;
}
.icon-check {
  color: red;
}
.icon-close {
  color: green;
}
</style>